﻿using System;
using KuiHuaBaoDian.Services.Lockstep;
using Runtime.Models;
using Runtime.Services.Battle;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleAttack;

namespace Runtime.Services.BattleSkill {

    public abstract partial class DFR_BattleSkillServiceTD {

        private sealed class CountdownBuff : DFR_BattleEffectHolder, IDFR_BattleBuffProvider {

            private sealed class BulletProvider : IDFR_BattleAttackBulletProvider {

                public string BulletFlyAssetKey { get; } = null;

                public string BulletHitAssetKey { get; init; }

                public F64 BulletFlySpeed { get; } = F64.Zero;
            }

            IDFR_BattleBuffProviderSetter IDFR_BattleBuffProvider.AsSetter() => throw new NotSupportedException();

            bool IDFR_BattleBuffProvider.IsEnablePersistence => false;

            public delegate void CompleteDelegate();
            public event CompleteDelegate Complete;

            [Autowired]
            private readonly IDFR_BattleComplexData m_Countdown;

            [Autowired]
            private readonly IDFR_BattleData m_CountdownBase;

            [Autowired]
            private readonly IDFR_BattleData m_CountdownAdditional;

            public DFR_BattleEntityInstanceID OwnerEntityInstanceID { get; private set; }

            DFR_BattleEntityInstanceID IDFR_BattleBuffProvider.SourceEntityInstanceID => DFR_BattleEntityInstanceID.Empty;

            public DFR_BattleEntityInstanceID EntityInstanceID { get; private set; }

            private DFR_BattleEntityInstanceID m_TargetInstanceID;

            private IDFR_BattleBuffProviderSetter m_BuffProvider;

            private IDFR_BattleAttackSnapshot m_Snapshot;

            private bool m_IsDOT;
            private F64 m_Timer = F64.Zero;

            public void Initialize(IDFR_BattleEffectModelBase effectModel, DFR_BattleEntityInstanceID targetInstanceID, bool isDOT) {
                m_IsDOT = isDOT;
                m_TargetInstanceID = targetInstanceID;
                OwnerEntityInstanceID = effectModel.OwnerEntityInstanceID;
                EntityInstanceID = new() { ID = effectModel.EntityInstanceID.ID };
                BattleSkillServiceTD.Instance.AddEffectModel(EntityInstanceID, effectModel);
                var buffProvider = effectModel.AsBuffProvider();
                m_BuffProvider = KHBD.TypeMap.Instantiate<IDFR_BattleBuffProviderSetter>();
                (m_BuffProvider as IDFR_BattleBuffProviderInternal).Initialize(EntityInstanceID, false, OwnerEntityInstanceID, effectModel.EntityInstanceID);
                m_BuffProvider.AttachBuff(buffProvider);
                m_CountdownBase.Value = effectModel.Duration;
                m_CountdownAdditional.Value = F64.Zero;
                m_Countdown.Initialize(F64.Zero, F64.One, F64.Zero);
                m_Countdown.Base.Add(m_CountdownBase);
                m_Countdown.Additional.Add(m_CountdownAdditional);
                SetModelAssetKey(effectModel.ModelAssetKey);
                if (DFR_BattleTD.DataCenter.Models.AttackSourceDictionary.TryGetValue(OwnerEntityInstanceID, out var attackSourceModel)) {
                    m_Snapshot = new IDFR_BattleSkillServiceTD.Snapshot(buffProvider);
                    m_Snapshot.Initialize(attackSourceModel.AsAttacker(), null, false, false, 0, null, false);
                }
            }

            override protected void Dispose() {
                BattleSkillServiceTD.Instance.RemoveEffectModel(EntityInstanceID);
                m_BuffProvider.Dispose();
                m_BuffProvider = null;
                OwnerEntityInstanceID = DFR_BattleEntityInstanceID.Empty;
                EntityInstanceID = DFR_BattleEntityInstanceID.Empty;
                m_TargetInstanceID = DFR_BattleEntityInstanceID.Empty;
                Complete = null;
                if (m_Snapshot != null) {
                    m_Snapshot.Dispose();
                    m_Snapshot = null;
                }
                base.Dispose();
            }

            public void OnLogicFrame() {
                if (!IsDisposed
                //&& DFR.DataCenter.Models.Battle.WarriorDictionary.TryGetValue(m_TargetInstanceID, out var warriorModel1) && warriorModel1.AsAttackTarget().IsEnabled
                ) {
                    var deltaTime = DFR_BattleBase.DataCenter.Models.IsCoolDownCanElapse ? LockstepService.Instance.FrameLength : F64.Zero;
                    m_CountdownAdditional.Value -= deltaTime;
                    if (m_IsDOT) {
                        m_Timer += deltaTime;
                        if (m_Timer >= F64.One) {
                            m_Timer -= F64.One;
                            Timer();
                        }
                    }
                }
                if (!IsDisposed && (m_IsManualCompleted || m_Countdown.Value <= F64.Zero)
                //&& (
                //(DFR.DataCenter.Models.Battle.WarriorDictionary.TryGetValue(m_TargetInstanceID, out var warriorModel2) && warriorModel2.AsAttackTarget().IsEnabled)
                //|| (DFR.DataCenter.Models.Battle.MonsterDictionary.TryGetValue(m_TargetInstanceID, out var monsterModel))
                //)
                ) {
                    Complete?.Invoke();
                }
            }

            private void Timer() {
                if (DFR_BattleTD.DataCenter.Models.AttackTargetDictionary.TryGetValue(m_TargetInstanceID, out var attackTargetModel) && attackTargetModel.AsAttackTarget().IsEnabled) {
                    BattleAttackService.Instance.Hit(m_Snapshot, m_TargetInstanceID, attackTargetModel.AsAttackTarget(),
                        sourceModelDictionary: DFR_BattleTD.DataCenter.Models.AttackSourceDictionary.AsBase(),
                        targetModelDictionary: DFR_BattleTD.DataCenter.Models.AttackTargetDictionary.AsBase());
                    if (HasModelAsset) {
                        BattleServiceBase.Instance.AttachHolder(this, attackTargetModel.MapPosition, IDFR_BattleSkillServiceBase.BATTLE_HOLDER_AUTO_KILL_TIME);
                    }
                }
            }

            private bool m_IsManualCompleted = false;
            public void ManualComplete() {
                m_IsManualCompleted = true;
            }

            public IDFR_ReadOnlyBattleData HPBase => m_BuffProvider.HPBase;

            public IDFR_ReadOnlyBattleData HPFactor => m_BuffProvider.HPFactor;

            public IDFR_ReadOnlyBattleData HPAdditional => m_BuffProvider.HPAdditional;

            public IDFR_ReadOnlyBattleData HPMaxBase => m_BuffProvider.HPMaxBase;

            public IDFR_ReadOnlyBattleData HPMaxFactor => m_BuffProvider.HPMaxFactor;

            public IDFR_ReadOnlyBattleData HPMaxAdditional => m_BuffProvider.HPMaxAdditional;

            public IDFR_ReadOnlyBattleData DamageHPMaxBase => m_BuffProvider.DamageHPMaxBase;

            public IDFR_ReadOnlyBattleData DamageHPMaxFactor => m_BuffProvider.DamageHPMaxFactor;

            public IDFR_ReadOnlyBattleData DamageHPMaxAdditional => m_BuffProvider.DamageHPMaxAdditional;

            public IDFR_ReadOnlyBattleData DamageHPBase => m_BuffProvider.DamageHPBase;

            public IDFR_ReadOnlyBattleData DamageHPFactor => m_BuffProvider.DamageHPFactor;

            public IDFR_ReadOnlyBattleData DamageHPAdditional => m_BuffProvider.DamageHPAdditional;

            public IDFR_ReadOnlyBattleData DamageBase => m_BuffProvider.DamageBase;

            public IDFR_ReadOnlyBattleData DamageFactor => m_BuffProvider.DamageFactor;

            public IDFR_ReadOnlyBattleData DamageAdditional => m_BuffProvider.DamageAdditional;

            public IDFR_ReadOnlyBattleData AttackBase => m_BuffProvider.AttackBase;

            public IDFR_ReadOnlyBattleData AttackFactor => m_BuffProvider.AttackFactor;

            public IDFR_ReadOnlyBattleData AttackAdditional => m_BuffProvider.AttackAdditional;

            public IDFR_ReadOnlyBattleData AttackBossAdditionalBase => m_BuffProvider.AttackBossAdditionalBase;

            public IDFR_ReadOnlyBattleData AttackBossAdditionalFactor => m_BuffProvider.AttackBossAdditionalFactor;

            public IDFR_ReadOnlyBattleData AttackBossAdditionalAdditional => m_BuffProvider.AttackBossAdditionalAdditional;

            public IDFR_ReadOnlyBattleData AttackSpeedBase => m_BuffProvider.AttackSpeedBase;

            public IDFR_ReadOnlyBattleData AttackSpeedFactor => m_BuffProvider.AttackSpeedFactor;

            public IDFR_ReadOnlyBattleData AttackSpeedAdditional => m_BuffProvider.AttackSpeedAdditional;

            public IDFR_ReadOnlyBattleData CriticalBase => m_BuffProvider.CriticalBase;

            public IDFR_ReadOnlyBattleData CriticalFactor => m_BuffProvider.CriticalFactor;

            public IDFR_ReadOnlyBattleData CriticalAdditional => m_BuffProvider.CriticalAdditional;

            public IDFR_ReadOnlyBattleData CriticalPowerBase => m_BuffProvider.CriticalPowerBase;

            public IDFR_ReadOnlyBattleData CriticalPowerFactor => m_BuffProvider.CriticalPowerFactor;

            public IDFR_ReadOnlyBattleData CriticalPowerAdditional => m_BuffProvider.CriticalPowerAdditional;

            public IDFR_ReadOnlyBattleData SpottingRangeBase => m_BuffProvider.SpottingRangeBase;

            public IDFR_ReadOnlyBattleData SpottingRangeFactor => m_BuffProvider.SpottingRangeFactor;

            public IDFR_ReadOnlyBattleData SpottingRangeAdditional => m_BuffProvider.SpottingRangeAdditional;

            public IDFR_ReadOnlyBattleData MoveSpeedBase => m_BuffProvider.MoveSpeedBase;

            public IDFR_ReadOnlyBattleData MoveSpeedFactor => m_BuffProvider.MoveSpeedFactor;

            public IDFR_ReadOnlyBattleData MoveSpeedAdditional => m_BuffProvider.MoveSpeedAdditional;

            public IDFR_ReadOnlyBattleData DefenseBase => m_BuffProvider.DefenseBase;

            public IDFR_ReadOnlyBattleData DefenseFactor => m_BuffProvider.DefenseFactor;

            public IDFR_ReadOnlyBattleData DefenseAdditional => m_BuffProvider.DefenseAdditional;

            public IDFR_ReadOnlyBattleData DodgeBase => m_BuffProvider.DodgeBase;

            public IDFR_ReadOnlyBattleData DodgeFactor => m_BuffProvider.DodgeFactor;

            public IDFR_ReadOnlyBattleData DodgeAdditional => m_BuffProvider.DodgeAdditional;

            public IDFR_ReadOnlyBattleData InfluenceAmountAdditional => m_BuffProvider.InfluenceAmountAdditional;
        }
    }
}
